#pragma once

#include <memory>

#include "common/json.h"
#include "common/file.h"
#include "util.h"


namespace evm { namespace http {

using namespace std;

using QueryParas = unordered_multimap<string, string>;

struct Request {
    HTTPMethod method{GET};
    string url;  // raw url
    string path;
    QueryParas query_paras;
    Headers headers;
    string body;
    Json json;
    Json path_paras;

    size_t content_length{};  // content-length parsed from header
    bool has_file{};  // if true, means request containing file stream
    string file_name;  // if empty, means reject receiving file
    function<void()> file_handler;  // if not empty, be called after receiving file successfully

    Request() = default;

    Request(HTTPMethod method, string url, string path, QueryParas query_paras,
            Headers headers, string body)
            : method(method), url(url), path(path), query_paras(query_paras),
              headers(headers), body(body) {
    }

    Request& operator=(Request&& r);

    void clear();

    void set_header(string field, string value) {
        headers.erase(field);
        headers.emplace(std::move(field), std::move(value));
    }

    string get_query(const string& field) const;  // field not found, return empty string

    bool has_query(const string& field) const;

    bool has_query(const string& field, const string& value) const;

    const string& get_header(const string &field) const;

    bool has_header(const string &field) const;

    bool has_header(const string &field, const string &value) const;

    auto operator[](const char* key) -> decltype(json[""]);
    auto operator[](const string& key) -> decltype(json[""]);

    string str() const;
};

}}
